﻿#include "stdafx.h"
#include "PhysicsTerrain.h"

_NAMESPACE_BEGIN

void TerrainShape::Create( const Terrain_Desc& desc,NxActorDesc& actorDesc,NxActor* pActor )
{
	terrainSize = desc.size;
	nRows = desc.nbRows;
	nColumns = desc.nbColumns;

	if(desc.nbColumns!=2)
		assert((desc.nbColumns-1)/2*2==desc.nbColumns-1);
	if(desc.nbRows!=2)
		assert((desc.nbRows-1)/2*2==desc.nbRows-1);

	NxHeightFieldDesc heightFieldDesc;
	heightFieldDesc.nbColumns		= desc.nbColumns;
	heightFieldDesc.nbRows			= desc.nbRows;
	heightFieldDesc.convexEdgeThreshold = 0;

	// 分配内存
	heightFieldDesc.samples			= new NxU32[desc.nbColumns*desc.nbRows];
	heightFieldDesc.sampleStride	= sizeof(NxU32);

	char* currentByte = (char*)heightFieldDesc.samples;

	//TexturePtr heightMap = TextureManager::getSingleton().load(desc.nameHeightmap,"General");

	//HardwarePixelBufferSharedPtr ptr = heightMap->getBuffer();
	//ptr->lock(HardwareBuffer::HBL_NORMAL);
	//const PixelBox &pb = ptr->getCurrentLock();

	//const unsigned char *data = (unsigned char *)pb.data;

	const size_t height = desc.height;
	const size_t width = desc.width;
	const size_t rowPitch = desc.width;

	FILE *fp = fopen(desc.nameHeightmap.c_str(),"rb");
	float* data = new float[height*width];
	int num = fread(data,sizeof(float),desc.height*desc.width,fp);
	assert(num != 0);
	fclose(fp);

	std::vector<std::vector<float> > table;
	std::vector<std::vector<float> > rotated;//旋转
	table.resize(desc.nbRows);
	rotated.resize(desc.nbRows);
	for (size_t i=0; i<desc.nbRows; i++)
	{
		table[i].resize(desc.nbColumns);
		rotated[i].resize(desc.nbColumns);
		for (size_t j=0; j<desc.nbColumns; j++)
		{
			table[i][j] = data[desc.nbColumns*i + j];
		}
	}
	for (size_t i=0; i<desc.nbRows; i++)
	{
		for (size_t j=0; j<desc.nbColumns; j++)
		{
			//rotated[desc.nbColumns-1-j][i] = table[i][j];
			rotated[j][desc.nbColumns-1-i] = table[i][j];
		}
	}

	for (NxU32 column = 0; column <desc.nbColumns; column++)
	{
//  	for (int column = desc.nbColumns-1; column >=0; column--)
//  	{
 		for (NxU32 row = 0; row <desc.nbRows; row++)
 		{
		//for (int row = desc.nbRows-1; row >=0; row--)
		//{
			NxReal s = NxReal(row) / NxReal(height);
			NxReal t = NxReal(column) / NxReal(width);
			
			NxI16 hei = rotated[column][row];/*data[rowPitch*column + row];*/

			NxHeightFieldSample* currentSample = (NxHeightFieldSample*)currentByte;
			currentSample->height = hei;

			int xDiff = column-width*0.75;
			int yDiff = row-height*0.75;

			currentSample->tessFlag = 0;

			int dist = abs(xDiff) + abs(yDiff);
			if (dist>8)
			{
				currentSample->materialIndex0 = 1;
				currentSample->materialIndex1 = 1;
			}
			else if (dist==8)
			{
				if (xDiff != 0 && yDiff != 0)
				{
					currentSample->materialIndex0 = xDiff<0 ? 1 : 2;
					currentSample->materialIndex1 = xDiff<0 ? 2 : 1;
					currentSample->tessFlag = (xDiff<0 != yDiff<0) ? 1 : 0;
				} 
				else 
				{
					currentSample->materialIndex0 = 1;
					currentSample->materialIndex1 = 1;
				}
			} 
			else
			{
				currentSample->materialIndex0 = 2;
				currentSample->materialIndex1 = 2;
			}
			currentByte += heightFieldDesc.sampleStride;


			currentSample->materialIndex0 = 0; // Implement physical terrain materials
			currentSample->materialIndex1 = 0;
		}
	}
	//ptr->unlock();

	NxHeightField* heightField = PhysicsManager::Instance()->GetPhysicsSDK()->createHeightField(heightFieldDesc);

	// data has been copied, we can free our buffer
	delete [] heightFieldDesc.samples;

	NxHeightFieldShapeDesc heightFieldShapeDesc;
	heightFieldShapeDesc.heightField	= heightField;
	heightFieldShapeDesc.shapeFlags		= NX_SF_FEATURE_INDICES | NX_SF_VISUALIZATION;
	heightFieldShapeDesc.heightScale	= desc.size.y;
	heightFieldShapeDesc.rowScale		= desc.size.z / NxReal(desc.nbRows-1);
	heightFieldShapeDesc.columnScale	= desc.size.x / NxReal(desc.nbColumns-1);
	//heightFieldShapeDesc.meshFlags	= NX_MESH_SMOOTH_SPHERE_COLLISIONS;
	heightFieldShapeDesc.materialIndexHighBits = 0;
	heightFieldShapeDesc.holeMaterial = 2;

	assert(heightFieldShapeDesc.isValid());		
	actorDesc.shapes.pushBack(&heightFieldShapeDesc);
	actorDesc.body		   = NULL;
	//actorDesc.globalPose.M.rotX(D3DX_PI);
	actorDesc.globalPose.t.setx(desc.pos.x);
	actorDesc.globalPose.t.setz(desc.pos.z);
	actorDesc.globalPose.t.sety(desc.pos.y);

	assert(actorDesc.isValid());
	pOwner->CreateActor(false);

	pOwner->GetActor()->setGroup(Actor_Group_Terrain);

	delete[] data;
}

void TerrainShape::SetShapePtr( NxShape* p )
{
	PhysXPrimitive::SetShapePtr(p);
	p->setGroup(Shape_Group_Terrain);
	pshape=dynamic_cast<NxHeightFieldShape*>(p);
	assert(pshape);
}

_NAMESPACE_END